﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Linq;
using System.Text;
using System.Drawing;
using GRV11;

namespace gpuimp.core
{
    public enum SelectionState
    {
        None,
        Rectangle,
        Ellipse,
        Area,
        Lasso
    }

    public class Selection
    {
        public GRTexture selectionMask;
        Canvas canvas;
        Bitmap bitmap;
        PointF min, max;

        public Selection(Canvas c)
        {
            canvas = c;
            selectionMask = new GRTexture();
            clearSelection();
        }

        public void clearSelection()
        {
            mesh.Clear();

            if (bitmap == null)
                bitmap = new Bitmap(canvas.ImageSize.X, canvas.ImageSize.Y);
            for (int x = 0; x < canvas.ImageSize.X; x++)
            {
                for (int y = 0; y < canvas.ImageSize.Y; y++)
                {
                    bitmap.SetPixel(x, y, Color.White);
                }
            }
            
            selectionMask.CreateTextureFromBitmap(CanvasManager.gr, bitmap, false);
        }

        public void selectBox(Point min, Point max, PointF windowSize)
        {
            if (bitmap == null)
                bitmap = new Bitmap(canvas.ImageSize.X, canvas.ImageSize.Y);

            this.min = min;
            this.max = max;
            GenerateMesh(false, min, max, windowSize);

            //account for canvas position and scale
            float dW = canvas.ImageSize.X - windowSize.X;
            float dH = canvas.ImageSize.Y - windowSize.Y;
            Point offset = new Point();
            offset.X = (int)(dW * 0.5f);
            //offset.X -= canvas.ImageSize.X / 2;
            offset.X -= canvas.Position.X;
            offset.Y = (int)(dH * 0.5f);
            //offset.Y -= canvas.ImageSize.Y / 2;
            offset.Y -= canvas.Position.Y;

            min.X += offset.X;
            min.Y += offset.Y;
            max.X += offset.X;
            max.Y += offset.Y;

            //flip the y coordinates
            int temp = min.Y;
            min.Y = canvas.ImageSize.Y - max.Y;
            max.Y = canvas.ImageSize.Y - temp;
            
            for (int x = 0; x < canvas.ImageSize.X; x++)
            {
                for (int y = 0; y < canvas.ImageSize.Y; y++)
                {
                    if (x <= max.X && x >= min.X && y <= max.Y && y >= min.Y)
                        bitmap.SetPixel(x, y, Color.White);
                    else
                        bitmap.SetPixel(x, y, Color.Black);
                }
            }

            selectionMask.CreateTextureFromBitmap(CanvasManager.gr, bitmap, false);

        }
        PointF ConvertToWorldSpace(PointF point, PointF windowSize)
        {
            //account for canvas position and scale
            float dW = canvas.ImageSize.X - windowSize.X;
            float dH = canvas.ImageSize.Y - windowSize.Y;
            PointF offset = new PointF();
            offset.X = dW;
            offset.X -= canvas.ImageSize.X;
            offset.X -= canvas.Position.X;
            offset.Y = dH;
            offset.Y -= canvas.ImageSize.Y;
            offset.Y -= canvas.Position.Y;

            point.X *= 2;
            point.Y *= 2;
            point.X += offset.X;
            point.Y += offset.Y;
            return point;
        }
        public void GenerateMesh(bool isEllipse, PointF p1, PointF p2, PointF windowSize)
        {
            mesh.Clear();
            //make sure min and max are actually min and max
            if (p1.X > p2.X || p1.Y > p2.Y)
            {
                float temp;
                if (p1.X > p2.X)
                {
                    temp = p1.X;
                    p1.X = p2.X;
                    p2.X = temp;
                }
                if (p1.Y > p2.Y)
                {
                    temp = p1.Y;
                    p1.Y = p2.Y;
                    p2.Y = temp;
                }
            }
            Console.WriteLine(windowSize);
            p1 = ConvertToWorldSpace(p1, windowSize);
            p2 = ConvertToWorldSpace(p2, windowSize);

            if (!isEllipse)
            {
                mesh.Add(new Vertex(p1.X, p1.Y, 0, 0, 0));
                mesh.Add(new Vertex(p2.X, p1.Y, 0, 0, 0));
                mesh.Add(new Vertex(p2.X, p2.Y, 0, 0, 0));
                mesh.Add(new Vertex(p1.X, p2.Y, 0, 0, 0));
            }
            else
            {
                float percent = 0;
                PointF center = new PointF((p1.X + p2.X) * 0.5f, (p1.Y + p2.Y) * 0.5f);
                PointF size = new PointF(p2.X - p1.X, p2.Y - p1.Y);
                size.X *= 0.5f;
                size.Y *= 0.5f;
                for (int i = 0; i < 100; i++)
                {
                    percent = i * 0.01f;
                    mesh.Add(new Vertex((float)(center.X + size.X * Math.Cos(percent * 6.28f)), (float)(center.Y + size.Y * Math.Sin(percent * 6.28)), 0, 0, 0));
                }
            }
        }
        public void selectEllipse(Point min, Point max, PointF windowSize)
        {
            if (bitmap == null)
                bitmap = new Bitmap(canvas.ImageSize.X, canvas.ImageSize.Y);

            this.min = min;
            this.max = max;
            GenerateMesh(true, min, max, windowSize);

            //account for canvas position and scale
            float dW = canvas.ImageSize.X - windowSize.X;
            float dH = canvas.ImageSize.Y - windowSize.Y;
            Point offset = new Point();
            offset.X = (int)(dW * 0.5f);
            //offset.X -= canvas.ImageSize.X / 2;
            offset.X -= canvas.Position.X;
            offset.Y = (int)(dH * 0.5f);
            //offset.Y -= canvas.ImageSize.Y / 2;
            offset.Y -= canvas.Position.Y;

            min.X += offset.X;
            min.Y += offset.Y;
            max.X += offset.X;
            max.Y += offset.Y;

            //flip the y coordinates
            int temp = min.Y;
            min.Y = canvas.ImageSize.Y - max.Y;
            max.Y = canvas.ImageSize.Y - temp;

            Point center = new Point((min.X + max.X) / 2, (min.Y + max.Y) / 2);
            Point ab = new Point( (max.X - min.X) / 2, (max.Y - min.Y) / 2);
            ab.X *= ab.X;
            ab.Y *= ab.Y;
            float value;
            for (int x = 0; x < canvas.ImageSize.X; x++)
            {
                for (int y = 0; y < canvas.ImageSize.Y; y++)
                {
                    value = (x - center.X) * (x - center.X) / (float)ab.X + (y - center.Y) * (y - center.Y) / (float)ab.Y;
                    //if (x <= max.X && x >= min.X && y <= max.Y && y >= min.Y)
                    if(value <= 1)
                        bitmap.SetPixel(x, y, Color.White);
                    else
                        bitmap.SetPixel(x, y, Color.Black);
                }
            }

            selectionMask.CreateTextureFromBitmap(CanvasManager.gr, bitmap, false);
            this.min = min;
            this.max = max;
        }

        public void selectWipe()
        {
            if (bitmap == null)
                bitmap = new Bitmap(canvas.ImageSize.X, canvas.ImageSize.Y);

            for (int x = 0; x < canvas.ImageSize.X; x++)
            {
                int amount = (int)((float)x / (float)canvas.ImageSize.X * 255.0f);

                for (int y = 0; y < canvas.ImageSize.Y; y++)
                    bitmap.SetPixel(x, y, Color.FromArgb(amount, amount, amount));
            }

            selectionMask.CreateTextureFromBitmap(CanvasManager.gr, bitmap, false);
        }

        List<Vertex> mesh = new List<Vertex>();
        public void Draw(GR gr)
        {
            if (mesh.Count >= 3)
            {
                gr.glLineWidth(1.0f);
                gr.glBegin(GR.GL_LINE_STRIP);
                gr.glColor3f(0.4f, 0.4f, 0.4f);
                foreach (Vertex v in mesh)
                    gr.glVertex3f(v.X, v.Y, v.Z);
                gr.glVertex3f(mesh[0].X, mesh[0].Y, mesh[0].Z); //connect to beginning
                gr.glEnd();
            }
        }
    }
}